home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / support / monitor.c next >
Encoding:
C/C++ Source or Header  |  1993-04-17  |  21.3 KB  |  1,047 lines

  1. /*    
  2.  *     POSTGRES Terminal Monitor
  3.  *    
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include <sys/file.h>
  8. #include <sys/types.h>
  9. #include <sys/uio.h>
  10. #include <signal.h>
  11.  
  12. #include "tmp/c.h"
  13. #include "strings.h"
  14. #include "tmp/simplelists.h"
  15. #include "tmp/libpq-fe.h"
  16. #include "utils/log.h"
  17. #include <errno.h>
  18.  
  19. RcsId("$Header: /private/postgres/src/support/RCS/monitor.c,v 1.55 1992/08/21 05:07:48 mer Exp $");
  20.  
  21.  
  22. /* Global Declarations 
  23.  *
  24.  *  These variables are defined in pqexec.c and
  25.  *  are used in the fe/be comm. protocol
  26.  *   
  27.  */
  28. extern char    *getenv();
  29. extern char    *PQhost;     /* machine on which the backend is running */
  30. extern char    *PQport;     /* comm. port with the postgres backend. */
  31. extern char    *PQtty;      /* the tty where postgres msgs are displayed */
  32. extern char    *PQdatabase; /* the postgres db to access.  */
  33. extern int    PQportset;   /* 1 if comm. with backend is set */
  34. extern int    PQxactid;    /* xact id of the current xact.  */
  35. extern char    *PQinitstr;  /* initialisation string sent to backend */
  36. extern int    PQtracep;    /* set to 1 if debugging is set */
  37.  
  38.  
  39. /* 
  40.  * monitor.c  -- function prototypes (all private)
  41.  */
  42. int do_input ARGS((FILE *ifp ));
  43. int init_tmon ARGS((void ));
  44. int welcome ARGS((void ));
  45. int handle_editor ARGS((void ));
  46. int handle_shell ARGS((void ));
  47. int print_tuples ARGS((char *pname ));
  48. int handle_send ARGS((void ));
  49. int handle_execution ARGS((char *query ));
  50. int handle_one_command ARGS((char *command ));
  51. int handle_file_insert ARGS((FILE *ifp ));
  52. int handle_print ARGS((void ));
  53. int handle_exit ARGS((int exit_status ));
  54. int handle_clear ARGS((void ));
  55. int handle_print_time ARGS((void ));
  56. int handle_write_to_file ARGS((void ));
  57. int handle_help ARGS((void ));
  58. int stuff_buffer ARGS((char c ));
  59. void argsetup ARGS((int *argcP, char ***argvP));
  60.  
  61. /*      
  62.  *          Functions which maintain the logical query buffer in
  63.  *          /tmp/PQxxxxx.  It in general just does a copy from input
  64.  *          to query buffer, unless it gets a backslash escape character.
  65.  *          It recognizes the following escapes:
  66.  *      
  67.  *          \e -- enter editor
  68.  *          \g -- "GO": submit query to POSTGRES
  69.  *          \i -- include (switch input to external file)
  70.  *          \p -- print query buffer 
  71.  *          \q -- quit POSTGRES
  72.  *          \r -- force reset (clear) of query buffer
  73.  *          \s -- call shell
  74.  *          \t -- print current time
  75.  *          \w -- write query buffer to external file
  76.  *          \h -- print the list of commands
  77.  *          \? -- print the list of commands
  78.  *          \\ -- produce a single backslash in query buffer
  79.  *      
  80.  */
  81.  
  82. /*
  83.  *   Declaration of global variables (but only to the file monitor.c
  84.  */
  85.  
  86. #ifdef linux
  87. /*
  88.  * Is there any default directory for vi under Linux? I don't think so.
  89.  */
  90. #define DEFAULT_EDITOR "vi"
  91. #else
  92. #define DEFAULT_EDITOR "/usr/ucb/vi"
  93. #endif
  94. static char *user_editor;     /* user's desired editor  */
  95. static int tmon_temp;         /* file descriptor for temp. buffer file */
  96. static char *pid_string;
  97. static char *tmon_temp_filename;
  98. static char query_buffer[8192];  /* Max postgres buffer size */
  99. bool RunOneCommand = false;
  100. bool Debugging;
  101. bool Verbose;
  102. bool Silent;
  103. bool TerseOutput = false;
  104. bool PrintAttNames = true;
  105.  
  106. extern char *optarg;
  107. extern int optind,opterr;
  108. extern FILE *debug_port;
  109.  
  110. /*
  111.  *  As of release 4, we allow the user to specify options in the environment
  112.  *  variable PGOPTION.  These are treated as command-line options to the
  113.  *  terminal monitor, and are parsed before the actual command-line args.
  114.  *  The arge struct is used to construct an argv we can pass to getopt()
  115.  *  containing the union of the environment and command line arguments.
  116.  */
  117.  
  118. typedef struct arge {
  119.     char    *a_arg;
  120.     struct arge    *a_next;
  121. } arge;
  122.  
  123. main(argc,argv)
  124.      int argc;
  125.      char **argv;
  126. {
  127.     int c;
  128.     int errflag = 0;
  129.     char *progname;
  130.     char *debug_file;
  131.     char *dbname;
  132.     char *command;
  133.     int exit_status = 0;
  134.  
  135.     /* 
  136.      * Processing command line arguments.
  137.      *
  138.      * h : sets the hostname.
  139.      * p : sets the coom. port
  140.      * t : sets the tty.
  141.      * o : sets the other options. (see doc/libpq)
  142.      * d : enable debugging mode.
  143.      * q : run in quiet mode
  144.      * Q : run in VERY quiet mode (no output except on errors)
  145.      * c : monitor will run one POSTQUEL command and exit
  146.      *
  147.      * T : terse mode - no formatting
  148.      * N : no attribute names - only columns of data
  149.      *     (these two options are useful in conjunction with the "-c" option
  150.      *      in scripts.)
  151.      */
  152.  
  153.     progname = *argv;
  154.     Debugging = false;
  155.     Verbose = true;
  156.     Silent = false;
  157.  
  158.     /* prepend PGOPTION, if any */
  159.     argsetup(&argc, &argv);
  160.  
  161.     while ((c = getopt(argc, argv, "h:p:t:d:qTNQc:")) != EOF) {
  162.     switch (c) {
  163.         case 'h' :
  164.           PQhost = optarg;
  165.           break;
  166.         case 'p' :
  167.           PQport = optarg;
  168.           break;
  169.         case 't' :
  170.           PQtty = optarg;
  171.           break;
  172.         case 'T' :
  173.           TerseOutput = true;
  174.           break;
  175.         case 'N' :
  176.           PrintAttNames = false;
  177.           break;
  178.         case 'd' :
  179.  
  180.           /*
  181.            *  When debugging is turned on, the debugging messages
  182.            *  will be sent to the specified debug file, which
  183.            *  can be a tty ..
  184.            */
  185.  
  186.           Debugging = true;
  187.           debug_file = optarg;
  188.           debug_port = fopen(debug_file,"w+");
  189.           if (debug_port == NULL) {
  190.           fprintf(stderr,"Unable to open debug file %s \n", debug_file);
  191.           exit(1);
  192.           }
  193.           PQtracep = 1;
  194.           break;
  195.         case 'q' :
  196.           Verbose = false;
  197.           break;
  198.         case 'Q' :
  199.           Verbose = false;
  200.           Silent = true;
  201.           break;
  202.         case 'c' :
  203.           Verbose = false;
  204.           Silent = true;
  205.           RunOneCommand = true;
  206.           command = optarg;
  207.           break;
  208.         case '?' :
  209.         default :
  210.           errflag++;
  211.           break;
  212.     }
  213.     }
  214.  
  215.     if (errflag ) {
  216.       fprintf(stderr, "usage: %s [-h host] [-p port] [-t logfile] [-d debugfile] [-q]\n", progname);
  217.       fprintf(stderr, "\t[-T] [-N] [-Q] [-c command] [dbname]\n");
  218.       fflush(stderr);
  219.       exit(2);
  220.     }
  221.  
  222.     /* find database */
  223.     if ((dbname = argv[optind]) == (char *) NULL) {
  224.     if ((dbname = getenv("DATABASE")) == (char *) NULL) {
  225.         if ((dbname = getenv("USER")) == (char *) NULL) {
  226.         fprintf(stderr, "%s: no database name specified\n", progname);
  227.         fflush(stderr);
  228.         exit (2);
  229.         }
  230.     }
  231.     }
  232.  
  233.     PQsetdb(dbname);
  234.  
  235.     /* print out welcome message and start up */
  236.     welcome();
  237.     init_tmon(); 
  238.  
  239.     /* parse input */
  240.     if (RunOneCommand) {
  241.     exit_status = handle_one_command(command);
  242.     } else {
  243.     do_input(stdin);
  244.     }
  245.  
  246.     handle_exit(exit_status);
  247. }
  248.  
  249. do_input(ifp)
  250.     FILE *ifp;
  251. {
  252.     int c;
  253.     char escape;
  254.  
  255.     /*
  256.      *  Processing user input.
  257.      *  Basically we stuff the user input to a temp. file until
  258.      *  an escape char. is detected, after which we switch
  259.      *  to the appropriate routine to handle the escape.
  260.      */
  261.  
  262.     if (ifp == stdin) {
  263.     if (Verbose)
  264.         fprintf(stdout,"\nGo \n* ");
  265.     else {
  266.         if (!Silent)
  267.         fprintf(stdout, "* ");
  268.     }
  269.     }
  270.     while ((c = getc(ifp)) != EOF ) {
  271.     if ( c == '\\') {
  272.         /* handle escapes */
  273.         escape = getc(ifp);
  274.         switch( escape ) {
  275.           case 'e':
  276.         handle_editor();
  277.         break;
  278.           case 'g':
  279.         handle_send();
  280.         break;
  281.           case 'i':
  282.         handle_file_insert(ifp);
  283.         break;
  284.           case 'p':
  285.         handle_print();
  286.         break;
  287.           case 'q':
  288.         handle_exit(0);
  289.         break;
  290.           case 'r':
  291.         handle_clear();
  292.         break;
  293.           case 's':
  294.         handle_shell();
  295.         break;
  296.           case 't':
  297.         handle_print_time();
  298.         break;
  299.           case 'w':
  300.         handle_write_to_file();
  301.         break;
  302.           case '?':
  303.           case 'h':
  304.         handle_help();
  305.         break;
  306.           case '\\':
  307.         c = escape;
  308.         stuff_buffer(c); 
  309.         break;
  310.           default:
  311.         fprintf(stderr, "unknown escape given\n");
  312.         break;
  313.         } /* end-of-switch */
  314.         if (ifp == stdin && escape != '\\') {
  315.         if (Verbose)
  316.             fprintf(stdout,"\nGo \n* ");
  317.         else {
  318.             if (!Silent)
  319.             fprintf(stdout, "* ");
  320.         }
  321.         }
  322.     } else {
  323.         stuff_buffer(c); 
  324.     }
  325.     }
  326. }
  327. /*
  328.  * init_tmon()
  329.  *
  330.  * set the following :
  331.  *     user_editor, defaults to DEFAULT_EDITOR if env var is not set
  332.  */
  333.  
  334. init_tmon()
  335. {
  336.     if (!RunOneCommand)
  337.     {
  338.     char *temp_editor = getenv("EDITOR");
  339.     
  340.     if (temp_editor != NULL) 
  341.         user_editor = temp_editor;
  342.     else
  343.         user_editor = DEFAULT_EDITOR;
  344.  
  345.     tmon_temp_filename = malloc(20);
  346.     sprintf(tmon_temp_filename, "/tmp/PQ%d", getpid());
  347.     tmon_temp = open(tmon_temp_filename,O_CREAT | O_RDWR | O_APPEND,0666);
  348.     }
  349.  
  350.     /*
  351.      * Catch signals so we can delete the scratch file GK
  352.      * but only if we aren't already ignoring them -mer
  353.      */
  354.  
  355.     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  356.     signal(SIGHUP, handle_exit);
  357.     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  358.     signal(SIGQUIT, handle_exit);
  359.     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  360.     signal(SIGTERM, handle_exit);
  361.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  362.     signal(SIGINT, handle_exit);
  363. }
  364.  
  365. /*
  366.  *  welcome simply prints the Postgres welcome mesg.
  367.  */
  368.  
  369. welcome()
  370. {
  371.     if (Verbose) {
  372.     fprintf(stdout,"Welcome to the C POSTGRES terminal monitor\n");
  373.     }
  374. }
  375.  
  376.  
  377. /*
  378.  *  handle_editor()
  379.  *
  380.  *  puts the user into edit mode using the editor specified
  381.  *  by the variable "user_editor".
  382.  */
  383.  
  384. handle_editor()
  385. {
  386.     char edit_line[100];
  387.  
  388.     close(tmon_temp);
  389.     sprintf(edit_line,"%s %s",user_editor,tmon_temp_filename);
  390.     system(edit_line);
  391.     tmon_temp = open(tmon_temp_filename,O_CREAT | O_RDWR | O_APPEND,0666);
  392. }
  393.  
  394. handle_shell()
  395. {
  396.     char *user_shell;
  397.  
  398.     user_shell = getenv("SHELL");
  399.     if (user_shell != NULL) {
  400.         system(user_shell);
  401.     } else {
  402.         system("/bin/sh");
  403.     }
  404. }
  405. /*
  406.  * print_tuples()
  407.  *
  408.  * This is the routine that prints out the tuples that
  409.  * are returned from the backend.
  410.  * Right now all columns are of fixed length,
  411.  * this should be changed to allow wrap around for
  412.  * tuples values that are wider.
  413.  */
  414.  
  415. print_tuples ( pname)
  416.      char *pname;
  417. {
  418.     PortalBuffer *p;
  419.     int j,k,g,m,n,t,x;
  420.     int temp, temp1;
  421.     char *tborder;
  422.  
  423.     /* Now to examine all tuples fetched. */
  424.     
  425.     p = PQparray(pname);
  426.     g = PQngroups (p);
  427.     t = 0;
  428.     temp = 0;
  429.  
  430.     for (k =0; k < g-1; k++) {
  431.     temp += PQntuplesGroup(p,k);
  432.     }
  433.  
  434.     /* Now to print out the attribute names 
  435.      *
  436.      * XXX Cheap Hack. For now, we see only the last group
  437.      * of tuples.  This is clearly not the right
  438.      * way to do things !!
  439.      */
  440.  
  441.     n = PQntuplesGroup(p,g-1);  /* zero based index.  */
  442.     m = PQnfieldsGroup(p,g-1);
  443.     
  444.     if ( m > 0 ) {  /* only print tuples with at least 1 field.  */
  445.  
  446.     if (!TerseOutput)
  447.     {
  448.         temp1 = (int) m * 14;
  449.         tborder = malloc (temp1+1);
  450.         bzero(tborder, temp1+1);
  451.         for (x = 0; x <= temp1; x++) 
  452.             tborder[x] = '-';
  453.  
  454.         tborder[x] = '\0';
  455.         fprintf(stdout,"%s\n",tborder);
  456.     }
  457.  
  458.     for (x=0; x < m; x++) 
  459.     {
  460.         if (PrintAttNames && !TerseOutput)
  461.         {
  462.             fprintf(stdout,"| %-12s",PQfnameGroup(p,g-1,x));
  463.         }
  464.         else if (PrintAttNames)
  465.         {
  466.             fprintf(stdout," %-12s",PQfnameGroup(p,g-1,x));
  467.         }
  468.     }
  469.  
  470.     if (PrintAttNames && !TerseOutput)
  471.     {
  472.         fprintf(stdout, "|\n");
  473.         fprintf(stdout,"%s\n",tborder);
  474.     }
  475.     else if (PrintAttNames)
  476.     {
  477.         fprintf(stdout, "\n");
  478.     }
  479.  
  480.     /* Print out the tuples */
  481.     t += temp;
  482.     
  483.     for (x = 0; x < n; x++) {
  484.  
  485.         for(j = 0; j < m; j++) 
  486.         {
  487.             if (!TerseOutput)
  488.             {
  489.                 fprintf (stdout, "| %-12s", PQgetvalue(p,t+x,j));
  490.             }
  491.             else
  492.             {
  493.                 fprintf (stdout, " %-12s", PQgetvalue(p,t+x,j));
  494.             }
  495.         }
  496.                 
  497.  
  498.         if (!TerseOutput)
  499.         {
  500.             fprintf (stdout, "|\n");
  501.             fprintf(stdout,"%s\n",tborder);
  502.         }
  503.         else
  504.         {
  505.             fprintf(stdout, "\n");
  506.         }
  507.     }
  508.     }
  509. }
  510.  
  511.  
  512. /*
  513.  * handle_send()
  514.  *
  515.  * This is the routine that initialises the comm. with the
  516.  * backend.  After the tuples have been returned and 
  517.  * displayed, the query_buffer is cleared for the 
  518.  * next query.
  519.  *
  520.  */
  521.  
  522. #include <ctype.h>
  523. handle_send()
  524. {
  525.     char c  = (char)0;
  526.     off_t pos;
  527.     int cc = 0;
  528.     int i = 0;
  529.     bool InAComment = false;
  530.  
  531.     pos = lseek(tmon_temp,(off_t)0,L_SET);
  532.  
  533.     if (pos != 0)
  534.     fprintf(stderr, "Bogus file position\n");
  535.  
  536.     if (Verbose)
  537.     printf("\n");
  538.  
  539.     /* discard leading white space */
  540.     while ( ( cc = read(tmon_temp,&c,1) ) != 0 && isspace((int)c))
  541.     continue;
  542.  
  543.     if ( cc != 0 ) {
  544.     pos = lseek(tmon_temp,(off_t)-1,L_INCR);
  545.     }
  546.     query_buffer[0] = 0;
  547.  
  548.     /*
  549.      *  Stripping out comments (if any) from the query (should really be
  550.      *  handled in the parser, of course).
  551.      */
  552.     while ( ( cc = read(tmon_temp,&c,1) ) != 0) {
  553.     if (!InAComment) {
  554.         switch(c) {
  555.           case '\n':
  556.           query_buffer[i++] = ' ';
  557.           break;
  558.           case '/':
  559.         {
  560.             int temp; 
  561.             char temp_c;
  562.             if ((temp = read(tmon_temp,&temp_c,1)) != 0) {
  563.             if (temp_c == '*' )
  564.                 InAComment = true;
  565.             else {
  566.                 query_buffer[i++] = c;
  567.                 query_buffer[i++] = temp_c;
  568.             }
  569.             }
  570.         }
  571.         break;
  572.           default:
  573.         query_buffer[i++] = c;
  574.         break;
  575.         }
  576.     } else {
  577.  
  578.         /*
  579.          *  in comment mode, drop chars until a '*' followed by a '/'
  580.          *  is found
  581.          */
  582.  
  583.         int temp;
  584.         char temp_c;
  585.  
  586.         if ( c == '*' ) {
  587.         if ((temp = read(tmon_temp,&temp_c,1)) != 0) {
  588.             if ( temp_c == '/')
  589.               InAComment = false;
  590.         } else {
  591.             elog(WARN,"ended tmon whilst in comment mode");
  592.         }
  593.         }
  594.     }
  595.     }
  596.  
  597.     if (query_buffer[0] == 0) {
  598.         query_buffer[0] = ' ';
  599.         query_buffer[1] = 0;
  600.     }
  601.  
  602.     if (Verbose)
  603.     fprintf(stdout,"Query sent to backend is \"%s\"\n", query_buffer);
  604.     fflush(stderr);
  605.     fflush(stdout);
  606.     
  607.     /*
  608.      * Repeat commands until done.
  609.      */
  610.  
  611.     handle_execution(query_buffer);
  612.  
  613.     /* clear the query buffer and temp file -- this is very expensive */
  614.     handle_clear();
  615.     bzero(query_buffer,i);
  616. }
  617.  
  618. /*
  619.  * Actually execute the query in *query.
  620.  *
  621.  * Returns 0 if the query finished successfully, 1 otherwise.
  622.  */
  623.  
  624. int
  625. handle_execution(query)
  626.  
  627. char *query;
  628.  
  629. {
  630.     bool done = false;
  631.     bool entering = true;
  632.     char *pstring1;
  633.     char pstring[256];
  634.     int nqueries = 0;
  635.     int retval = 0;
  636.  
  637.     while (!done) {
  638.  
  639.         if (entering) {
  640.         pstring1 = PQexec(query); 
  641.     fflush(stdout);
  642.     fflush(stderr);
  643.         entering = false;
  644.     } 
  645.  
  646.     strcpy(pstring, pstring1);
  647.  
  648.         switch(pstring[0]) {
  649.         case 'A':
  650.         case 'P':
  651.             print_tuples( &(pstring[1]));
  652.             PQclear(&(pstring[1]));
  653.             pstring1 = PQexec(" ");
  654.             nqueries++;
  655.             break;
  656.             
  657.         case 'E':
  658.             elog (FATAL,&(pstring[1]));
  659.             retval = 1;
  660.             break;
  661.             
  662.         case 'C':
  663.         if (!Silent)
  664.         fprintf(stdout,"%s",&(pstring[1]));
  665.             if (!Verbose && !Silent)
  666.         fprintf(stdout,"\n");
  667.             pstring1 = PQexec(" ");
  668.             nqueries++;
  669.             break;
  670.             
  671.         case 'I':
  672.             PQFlushI(nqueries - 1);
  673.             done = true;
  674.             break;
  675.             
  676.         case 'R':
  677.             done = true;
  678.             retval = 1;
  679.             break;
  680.  
  681.         case 'B':
  682.             {
  683.                 char s[100];
  684.  
  685.                 s[0] = ' ';
  686.  
  687.         if (!Silent)
  688.             fprintf(stdout, "Copy command returns...\n");
  689.  
  690.                 while (s[0] != '.')
  691.                 {
  692.                     PQgetline(s, 100);
  693.             if (s[0] != '.') fprintf(stdout, "%s\n", s);
  694.         }
  695.             }
  696.         PQendcopy();
  697.         done = 1;
  698.         break;
  699.     case 'D':
  700.         {
  701.                 char s[8192];
  702.         char c;
  703.  
  704.                 s[0] = ' ';
  705.  
  706.  
  707.         if (!Silent) {
  708.             fprintf(stdout, "Enter info followed by a newline\n");
  709.             fprintf(stdout, "End with a dot on a line by itself.\n");
  710.         }
  711.         /*
  712.          * eat inevitable newline still in input buffer
  713.          *
  714.          * XXX the 'inevitable newline' is not always present
  715.          *     for example `cat file | monitor -c "copy from stdin"
  716.          */
  717.  
  718.         if ((c = getchar()) != '\n')
  719.         {
  720.             s[0] = c;
  721.             gets(&s[1]);
  722.             PQputline(s);
  723.             PQputline("\n");
  724.         }
  725.  
  726.         fflush(stdin);
  727.                 while (s[0] != '.')
  728.                 {
  729.             if (!Silent)
  730.             fprintf(stdout, ">> ");
  731.             if (gets(s) == (char *)NULL)
  732.             {
  733.             PQputline(".\n");
  734.             break;
  735.             }
  736.             PQputline(s);
  737.             PQputline("\n");
  738.         }
  739.             }
  740.         PQendcopy();
  741.             done = true;
  742.         break;
  743.         default:
  744.             fprintf(stderr,"unknown type\n");
  745.           }
  746.     fflush(stderr);
  747.     fflush(stdout);
  748.     }
  749.     return(retval);
  750. }
  751.  
  752. /*
  753.  * handle_one_command()
  754.  *
  755.  * allows a POSTQUEL command to be specified from the command line
  756.  */
  757.  
  758. handle_one_command(command)
  759.  
  760. char *command;
  761.  
  762. {
  763.     return(handle_execution(command));
  764. }
  765.  
  766. /*
  767.  * handle_file_insert()
  768.  *
  769.  * allows the user to insert a query file and execute it.
  770.  * NOTE: right now the full path name must be specified.
  771.  */
  772.  
  773. handle_file_insert(ifp)
  774.     FILE *ifp;
  775. {
  776.     char user_filename[50];
  777.     FILE *nifp;
  778.  
  779.     fscanf(ifp, "%s",user_filename);
  780.     nifp = fopen(user_filename, "r");
  781.     if (nifp == (FILE *) NULL) {
  782.         fprintf(stderr, "Cannot open %s\n", user_filename);
  783.     } else {
  784.         do_input(nifp);
  785.         fclose (nifp);
  786.     }
  787. }
  788.  
  789. /*
  790.  * handle_print()
  791.  *
  792.  * This routine prints out the contents (query) of the temp. file
  793.  * onto stdout.
  794.  */
  795.  
  796. handle_print()
  797. {
  798.     char c;
  799.     off_t pos;
  800.     int cc;
  801.  
  802.     pos = lseek(tmon_temp,(off_t)0,L_SET);
  803.  
  804.     if (pos != 0 )
  805.     fprintf(stderr, "Bogus file position\n");
  806.  
  807.     printf("\n");
  808.  
  809.     while ( ( cc = read(tmon_temp,&c,1) ) != 0) 
  810.     putchar(c);
  811.  
  812.     printf("\n");
  813. }
  814.  
  815.  
  816. /*
  817.  * handle_exit()
  818.  *
  819.  * ends the comm. with the backend and exit the tm.
  820.  */
  821.  
  822. handle_exit(exit_status)
  823.  
  824. int exit_status;
  825.  
  826. {
  827.     int unlink_status;
  828.  
  829.     if (Verbose)
  830.     fprintf(stdout,"I live to serve you.\n");
  831.  
  832.     if (!RunOneCommand) 
  833.     {
  834.         close(tmon_temp);
  835.         unlink(tmon_temp_filename);
  836.     }
  837.     PQfinish();   
  838.     exit(exit_status);
  839. }
  840.  
  841. /*
  842.  * handle_clear()
  843.  *
  844.  *  This routine clears the temp. file.
  845.  */
  846.  
  847. handle_clear()
  848. {
  849.     /* high cost */
  850.     close(tmon_temp);
  851.     tmon_temp = open(tmon_temp_filename,O_TRUNC|O_RDWR|O_CREAT ,0666);
  852. }
  853.  
  854. /*
  855.  * handle_print_time()
  856.  * prints out the date using the "date" command.
  857.  */
  858.  
  859. handle_print_time()
  860. {
  861.     system("date");
  862. }
  863.  
  864. /*
  865.  * handle_write_to_file()
  866.  *
  867.  * writes the contents of the temp. file to the
  868.  * specified file.
  869.  */
  870.  
  871. handle_write_to_file()
  872. {
  873.     char filename[50];
  874.     static char command_line[512];
  875.     int fd;
  876.     
  877.     scanf ("%s",filename);
  878.     sprintf(command_line,"cp -f %s %s",tmon_temp_filename,filename);
  879.     
  880.     if(filename == NULL)
  881.     fprintf(stderr, "error: filename is empty\n");
  882.     else
  883.     system(command_line);
  884. }
  885.  
  886. /*
  887.  *
  888.  * Prints out a help message.
  889.  *
  890.  */
  891.  
  892. handle_help()
  893. {
  894.     printf("Available commands include \n\n");
  895.     printf("\\e -- enter editor\n");
  896.     printf("\\g -- \"GO\": submit query to POSTGRES\n");
  897.     printf("\\i -- include (switch input to external file)\n");
  898.     printf("\\p -- print query buffer\n");
  899.     printf("\\q -- quit POSTGRES\n");
  900.     printf("\\r -- force reset (clear) of query buffer\n");
  901.     printf("\\s -- shell escape \n");
  902.     printf("\\t -- print current time\n");
  903.     printf("\\w -- write query buffer to external file\n");
  904.     printf("\\h -- print the list of commands\n");
  905.     printf("\\? -- print the list of commands\n");
  906.     printf("\\\\ -- produce a single backslash in query buffer\n");
  907.     fflush(stdin);
  908. }
  909.  
  910. /*
  911.  * stuff_buffer()
  912.  *
  913.  * writes the user input into the temp. file.
  914.  */
  915.  
  916. stuff_buffer(c)
  917.     char c;
  918. {
  919.     int cc;
  920.  
  921.     cc = write(tmon_temp,&c,1);
  922.  
  923.     if(cc == -1)
  924.     fprintf(stderr, "error writing to temp file\n");
  925. }
  926.  
  927. void
  928. argsetup(argcP, argvP)
  929.     int *argcP;
  930.     char ***argvP;
  931. {
  932.     int argc;
  933.     char **argv, **curarg;
  934.     char *eopts;
  935.     char *envopts;
  936.     int neopts;
  937.     char *start, *end;
  938.     arge *head, *tail, *cur;
  939.  
  940.     /* if no options specified in environment, we're done */
  941.     if ((envopts = getenv("PGOPTION")) == (char *) NULL)
  942.     return;
  943.  
  944.     if ((eopts = (char *) malloc(strlen(envopts) + 1)) == (char *) NULL) {
  945.     fprintf(stderr, "cannot malloc copy space for PGOPTION\n");
  946.     fflush(stderr);
  947.     exit (2);
  948.     }
  949.  
  950.     (void) strcpy(eopts, envopts);
  951.  
  952.     /*
  953.      *  okay, we have PGOPTION from the environment, and we want to treat
  954.      *  them as user-specified options.  to do this, we construct a new
  955.      *  argv that has argv[0] followed by the arguments from the environment
  956.      *  followed by the arguments on the command line.
  957.      */
  958.  
  959.     head = cur = (arge *) NULL;
  960.     neopts = 0;
  961.  
  962.     for (;;) {
  963.     while (isspace(*eopts) && *eopts)
  964.         eopts++;
  965.  
  966.     if (*eopts == '\0')
  967.         break;
  968.  
  969.     if ((cur = (arge *) malloc(sizeof(arge))) == (arge *) NULL) {
  970.         fprintf(stderr, "cannot malloc space for arge\n");
  971.         fflush(stderr);
  972.         exit (2);
  973.     }
  974.  
  975.     end = start = eopts;
  976.  
  977.     if (*start == '"') {
  978.         start++;
  979.         while (*++end != '\0' && *end != '"')
  980.         continue;
  981.         if (*end == '\0') {
  982.         fprintf(stderr, "unterminated string constant in env var PGOPTION\n");
  983.         fflush(stderr);
  984.         exit (2);
  985.         }
  986.         eopts = end + 1;
  987.     } else if (*start == '\'') {
  988.         start++;
  989.         while (*++end != '\0' && *end != '\'')
  990.         continue;
  991.         if (*end == '\0') {
  992.         fprintf(stderr, "unterminated string constant in env var PGOPTION\n");
  993.         fflush(stderr);
  994.         exit (2);
  995.         }
  996.         eopts = end + 1;
  997.     } else {
  998.         while (!isspace(*end) && *end)
  999.         end++;
  1000.         if (isspace(*end))
  1001.         eopts = end + 1;
  1002.         else
  1003.         eopts = end;
  1004.     }
  1005.  
  1006.     if (head == (arge *) NULL) {
  1007.         head = tail = cur;
  1008.     } else {
  1009.         tail->a_next = cur;
  1010.         tail = cur;
  1011.     }
  1012.  
  1013.     cur->a_arg = start;
  1014.     cur->a_next = (arge *) NULL;
  1015.  
  1016.     *end = '\0';
  1017.     neopts++;
  1018.     }
  1019.  
  1020.     argc = *argcP + neopts;
  1021.  
  1022.     if ((argv = (char **) malloc(argc * sizeof(char *))) == (char **) NULL) {
  1023.     fprintf(stderr, "can't malloc space for modified argv\n");
  1024.     fflush(stderr);
  1025.     exit (2);
  1026.     }
  1027.  
  1028.     curarg = argv;
  1029.     *curarg++ = *(*argvP)++;
  1030.  
  1031.     /* copy env args */
  1032.     while (head != (arge *) NULL) {
  1033.     cur = head;
  1034.     *curarg++ = head->a_arg;
  1035.     head = head->a_next;
  1036.     free(cur);
  1037.     }
  1038.  
  1039.     /* copy rest of args from command line */
  1040.     while (--(*argcP))
  1041.     *curarg++ = *(*argvP)++;
  1042.  
  1043.     /* all done */
  1044.     *argvP = argv;
  1045.     *argcP = argc;
  1046. }
  1047.